#include "myQueue.h"
#include "initFunc.h"
#include "load_config.h"
#include "serverFucs.h"
#include "cmdParser.h"
#include "utils.h"
/*
   用于父进程与子进程通信的管道
   当父进程收到退出信号时，通知子进程，让子进程的线程有序退出，然后再依次退出
   */
int pipeFd[2];

// 通过异步拉起同步的方式来完成线程池所有功能
int main(int argc, char const *argv[])
{
    // 单元测试, 曾爽添加，其它开发人员可以删除
    printf("-------------------单元测试开始-------------------\n");
    // unitest_lsFunc();
    // unitest_lsFunc();
    // unitest_splitFunc();
    unitest_splitString();
    printf("-------------------单元测试结束-------------------\n");

    int ret = pipe(pipeFd);
    ERROR_CHECK(ret, -1, "pipe");
    pid_t pid = fork();
    if (pid != 0)
    {
        // 父进程执行逻辑
        // 关闭读端
        close(pipeFd[0]);
        signal(SIGINT, EXIT);
        wait(NULL);
        printf("子<-->父进程退出...\n");
        close(pipeFd[1]);
    }
    else
    {
        // 脱离前台进程组
        setpgid(0, 0);
        status_st threadControl; 
        initQueue(&threadControl);

        printf("line34---->afterinitQueue\n");

        // pthread_t threadIds[THREADNUM];// 没用
        initThreadControl(&threadControl, threadControl.thread_id);
        printf("threadControl.q.size:%d\n",threadControl.q.size);
        // initThreadControl(&threadControl,THREADNUM);
        // 初始化listenFd、bind、listen
        int listenFd;
        char ip[100] = {0};
        getparameter("ip", ip); // 获得ip
        char port[10] = {0};
        getparameter("port", port); // 获得端口

        // 初始化socket连接,bind绑定,linsten监听
        initSockBindListen(&listenFd, ip, atoi(port));
        printf("listenFd:%d\n",listenFd);
        // 创建epoll监听fd
        int epollFd = epoll_create(1);
        if (epollFd == -1)
        {
            perror("epoll");
            exit(-1);
        }
        // 增加监听对象
        addEpollObj(epollFd, listenFd);  // 监听新连接
        addEpollObj(epollFd, pipeFd[0]); // 监听管道退出信号

        while (1)
        {
            // 创建用户态下的就绪队列
            struct epoll_event events[10];
            printf("epoll_wait等待...\n");
            int readyNum = epoll_wait(epollFd, events, 10, -1);
            printf("epoll_wait等待结束...\n");
            for (int i = 0; i < readyNum; i++)
            {

                int curFd = events[i].data.fd;
                if (curFd == listenFd)
                {
                    int socketFd;
                    getSocktLink(curFd,&socketFd);
                    printf("连上来的socketFd:%d\n",socketFd);
                    // 有新的连接,判断用户名和密码是否能匹配得上
                    char user_buf[255] = {0};
                    char pwd_buf[255] = {0};
                    char send_msg[255] = { 0 };
                    strcpy(send_msg, "请输入用户名:");
                    int count = 0;
                    count = send(socketFd, send_msg, strlen(send_msg),0);
                    // 接收用户名
                    recv(socketFd, user_buf, sizeof(user_buf), 0);
                    memset(send_msg, 0, sizeof(send_msg));
                    strcpy(send_msg, "请输入密码:");
                    send(socketFd, send_msg, strlen(send_msg), 0);
                    // 接收密码
                    recv(socketFd, pwd_buf, sizeof(pwd_buf), 0);
                    printf("user_buf:%s pwd_buf:%s\n",user_buf,pwd_buf);
                    char _usrname[255] = { 0 };
                    memcpy(_usrname,user_buf,strlen(user_buf));
                    // 判断用户名和密码是否正确
                    bool isOk = judgeUserPwd(user_buf, pwd_buf);
                    if (isOk == true) // 用户名和密码正确
                    {
                        // 创建服务器工作的文件夹
                        // creat_folder(SERVER_PATH);
                        // 给客户端发送，验证成功
                        // memset(send_msg,0,sizeof(send_msg));

                        strcpy(send_msg,"验证成功");
                        send(socketFd,"1",1,0); // 发送1表示验证成功
                        // 创建用户根路径文件夹，并维护当前路径
                        char userWorkPath[1024] = { 0 };
                        sprintf(userWorkPath, "%s/%s", SERVER_PATH, _usrname);
                        printf("userWorkPath:%s\n",userWorkPath);
                        int ret = creat_folder(userWorkPath);
                        
                        // 加锁入队列
                        pthread_mutex_lock(&threadControl.mutex);
                        // 判断队列是否满了
                        if (isFull((&threadControl.q), THREADNUM) == true)
                        {
                            // 等待队列里位置了，唤醒队列
                            pthread_cond_wait(&threadControl.cond, &threadControl.mutex);
                        }
                        // 入队列
                        // 构建结构体
                        qNode_st* node = calloc(1,sizeof(qNode_st));
                        memcpy(node->curPath,"/",1);
                        printf("132:_usrname:%s\n",_usrname);
                        memcpy(node->username,_usrname,strlen(_usrname));
                        printf("134:node->username:%s\n",node->username);
                        node->fd = socketFd;
                        // 入队列
                        inQueue(&threadControl.q, node);
                        threadControl.q.size += 1;
                        printf("threadControl.q.size:%d\n",threadControl.q.size);
                        // 广播通知子线程 --> 改为通知一个子进程
                        pthread_cond_signal(&threadControl.cond);
                        // 解锁
                        pthread_mutex_unlock(&threadControl.mutex);
                        continue;
                    }
                    else // 用户名和密码不正确
                    {
                        // 给客户端发送验证失败，关闭连接
                        // memset(send_msg,0,sizeof(send_msg));
                        // strcpy(send_msg,"验证失败");
                        // send(socketFd,send_msg,strlen(send_msg),0);
                        send(socketFd,"0",1,0);
                        close(socketFd);
                        continue;
                    }
                }
                else
                {
                    // 收到管道信号
                    int flag;
                    read(pipeFd[0], &flag, sizeof(int));
                    if (flag == -1)
                    {
                        // 修改子进程退出标志位
                        threadControl.exitFlag = -1;
                        for (int j = 0; j < threadControl.threadNum; j++)
                        {
                            // 等待子进程退出
                            pthread_cond_broadcast(&threadControl.cond);
                            pthread_join(threadControl.thread_id[j], NULL);
                            printf("子线程退出+1\n");
                            // 销毁锁
                            pthread_mutex_destroy(&threadControl.mutex);
                        }
                        // 释放队列
                        destoryQueue(&threadControl.q);
                        // 销毁条件变量
                        pthread_cond_destroy(&threadControl.cond);
                        // 退出
                        exit(-1);
                    }
                }
            }
        }
    }
    return 0;
}

void EXIT(int sig_no)
{
    printf("收到退出信号:%d\n", sig_no);
    int exitFlag = -1;
    write(pipeFd[1], &exitFlag, sizeof(int));
}
